#ifndef _ROOM_H_
#define _ROOM_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

#include <json/json.h>

#include <map>
#include <set>
#include <list>
#include "mj.h"
#include "deck.h"
#include "json_packet.h"
#include "common_mjs.h"
#include "timer.h"
#include "chicken.h"
#include "network_base.h"

class Player;
class Client;

typedef enum
{
	STATE_READY = 0,
	STATE_MJ_FLASH = 1,
	STATE_DING_QUE = 2, //定缺
	STATE_PLAYING = 3,
	STATE_END = 4,
	STATE_MATCH_END = 5	//快抢赛结束状态
} State;


typedef struct
{
	unsigned int _seat_no;
	bool _occupied;
	Player *_player;

	void clear(void)
	{
		_seat_no = 0;
		_occupied = false;
		_player = NULL;
	}
} Seat;

typedef enum
{
	OP_NOT_CHECK = 0,
	OP_PASS = 1,
	OP_HU = 2,
	OP_GANG = 3,
	OP_PENG = 4,
} OP;

//其他玩家针对打出的牌操作检测
typedef struct
{
	Player *_player;			 //玩家指针
	bool _fangpao_hu_flag;    //是否可以放炮胡
	bool _fang_gang_flag;     //是否可以放杠
	bool _peng_flag;	         //是否可以碰

	OP _player_operation;	 //玩家操作，1PASS, 2选择胡，3选择杠，4选择碰

	void clear(void)
	{
		_player = NULL;
		_fangpao_hu_flag = false;
		_fang_gang_flag = false;
		_peng_flag = false;
		_player_operation = OP_NOT_CHECK;
	}

}P_CHECK;

//明杠时，其他玩家抢杠胡操作检测
typedef struct
{
	Player *_player; //玩家指针
	bool _qianggang_hu_flag;//是否可以抢杠胡
	OP _player_operation;   //0,未选择， 1 pass， 2 选择抢杠胡

	void clear(void)
	{
		_player = NULL;
		_qianggang_hu_flag = false;
		_player_operation = OP_NOT_CHECK;
	}
}P_CHECK_QGH;

typedef enum
{
	ET_ZI_MO = 1,//自摸
	ET_GANG_KAI_ZI_MO = 2,//杠开
	ET_FANG_PAO = 3,//放炮
	ET_FANG_RE_PAO = 4,//放热跑(杠炮)
	ET_QIANG_GANG = 5,//抢杠胡
	ET_HUANG_ZHUANG = 6,//黄庄
}END_TYPE;

//房间规则选择类
class RoomChooseRule
{
public:
	RoomChooseRule() :_match_id(0), _robot_in_wait_sec(0) {}
	int _match_id;
	int _robot_in_wait_sec;
};

class Room : public AsyncTimer
{
public:
	int							_gm;
	std::vector<Mj>				_gm_vec;						//管理员作弊牌
	ChickenGroup				_chicken_groups;				//鸡牌组
	std::list<int>				_match_reward;					//快抢赛奖品
	int							_match_id;						//快抢赛ID
	int							_isdissolution;					//要不要退房卡
	int							_clubid;						//属于哪个俱乐部
	int							_priv_uid;						//谁开的房间
	int							_password;
	int							_roomid;
	Seat                        _seats[4];
	std::map<int, Player*>      _players; //桌子中的所有玩家
	Deck                        _deck;
	int                         _dice[2];
	int                         _banker_seat;
	int                         _next_banker_seat;
	int                         _cur_seat;
	CommonMjs                   _comm_mjs;
	State                       _state;
	int                         _rec_id;				//如果是开房 >0为开房票流水ID

	Player*						_cur_outmj_player;		//本次出牌玩家
	Mj                          _cur_outmj;				//本次打出的牌 

	Player*						_cur_qgh_player; //可被抢杠胡的玩家
	Mj                   		_cur_qgh_mj;      //可被抢杠胡的麻将

	Player*						_cur_getin_player;		//最近摸牌的玩家
	Mj                          _cur_getin_mj;			//最近摸的一张牌

	int                         _rest_board;			//剩余可玩局数
	int                         _board_choose;			//总局数8局，4局
	int                         _player_num; //房间设置人数
	int                         _gang_mo_cnt; //杠牌后，牌堆结尾被摸掉的牌的张数

	P_CHECK                     _m_check[3]; //出牌玩家操作检测
	P_CHECK_QGH                 _m_check_qgh[3]; //抢杠胡操作检测


	GameTimer					_dissolution_confirm_timer;		//解散房间投票计时器
	GameTimer					_hu_flash_timer;		//胡牌动画延时
	GameTimer					_ding_que_timer;		//定缺计时器   
	GameTimer					_start_flash_timer;		//游戏开始动画延时
	GameTimer					_end_flash_timer;		//游戏结束动画延时


	int                         _gang_shang_pao_check_flag; // 杠上炮/杠上开花，检测标志(检测上一次操作是否有杠)

	int                         _end_type;				//游戏结束类型 1自摸 2放炮 3抢杠胡 4荒庄
	Mj                          _fangpaiji_mj;          //番鸡的鸡牌
	Player *					_chongfengji_player;    //冲锋鸡玩家指针
	Player *					_zherenji_from_player;  //打出 责任鸡玩家 
	Player *					_zherenji_to_player;    //碰了凑成 责任鸡玩家
	int							_zherenji_type;         //3碰的责任鸡，4杠的责任鸡


	int                 _min_access_gold;
	int                 _max_access_gold;
	int                 _base_gold;						//基础分倍数
	int                 _tai_fee;						//金币场台费
	bool				_has_timer;						//操作是否有超时

	time_t				_final_user_in_time;//最后一个用户加入进来的时间

protected:
	//关闭所有定时器
	void stopalltimer();
	//发送错误信息
	void SendError(int uid, int err_code, const string& err_msg);
public:
	Room(int id);
	virtual ~Room();

	//房间内路由选择
	int Dispatch(NetworkSessionBase* session, int uid);

	bool check(void* p_choose_rule/*筛选规则*/);
	void init();
	int init_private(int board_choose, int player_num);

	int init_gold_room(int _min_access_gold, int _max_access_gold, int _tai_fee, int _base_gold);
	//重置一个快抢赛
	int reset_shop_match(int choose);
	void reset();

	int player_enter_room(Player *player);

	int sit_down(Player *player);
	void stand_up(Player *player);
	Player* GetPlayer(int uid);
	//删除某用户
	int del_player(int uid);
	void del_all_players();
	int table_info_broadcast();
	int next_seat(int seat);
	Player *next_player(Player *player);
	Player *next_jiaopai_player(Player *player);

	void vector_to_json_array(std::vector<Mj> &mjs, JsonPacket &packet, string key);
	void form_player_all_mj_info_json(Player *player, JsonPacket &packet, string key);

	int start_ready();
	int start_game();
	int start_play();
	int start_play_2();
	//判断当前房间是否可以开始
	int judge_game_start();

	//计算赢番型
	int calculate_card_type(Player *player);

	//叫嘴玩家胡牌牌型(听牌)
	int calculate_jiaopai_card_type(Player *player);
	//结算快抢赛
	Json::Value calculate_quickly_match();
	int cardtype_to_base_score(int card_type);
	void calculate_cardtype_score(int card_type, Player *mo_player, Player *fangpao_player, Player* jiepao_player);

	void calculate_total_winlose_score(); //算分

	void do_gang_score();
	void do_huangzhuang();
	int game_end(int type);
	//单个通知
	int unicast(Player *p, JsonPacket &packet);
	//广播
	int broadcast(Player *p, JsonPacket &packet);
	//重新入座位的操作
	int handler_rebind(Player *player);
	//解散房间
	int do_dissolution_room();
	//摸一张牌给某用户 type=1就是开杠从最后面摸牌
	int getin_mj(Player *player, int type = 0);
	//在获得一张麻将后进行牌型检测
	int operate_check_after_getin_mj(Player *player);
	//在打出一张麻将后进行牌型检查
	int operate_check_after_putout_mj(Mj out_mj, Player *out_mj_player);
	//在碰牌后进行牌型检查
	int operate_check_after_peng_mj(Player *player);
	int operate_check_qiang_gang_hu(Mj gang_mj, Player* gang_player);

	int send_bar_operate_check_after_putout_mj(Player *player, int fangpaohu_flag, int _fang_gang_flag, int _peng_flag);
	int send_bar_operate_check_qiang_gang_hu(Player *player, Mj mj);
	//判断是否所有人都对操作盘做出应答
	bool outmj_all_check();
	//是否一炮多响
	bool if_ypsx();
	//一炮多响中判断是否所有可胡牌的人都对操作盘做出了应答
	bool outmj_ypsx_player_all_check();
	//一炮多响中判断是否有可胡牌的人选择了胡牌
	bool outmj_ypsx_player_check_has_hu();
	//判断是否所有人都对操作盘做出了pass的应答
	bool outmj_all_pass();
	//判断是否所有可胡牌的人都对操作盘做出了pass的应答
	bool outmj_hu_player_all_pass();

	int handler_ding_que_req(Player *player, NetworkSessionBase* session);
	int robot_do_din_que();
	int calculate_min_que(Player *player);
	int handler_player_operater_PUTOUT_MJ(Player *player, NetworkSessionBase* session);
	int handler_robot_auto_out_mj(Player *player, NetworkSessionBase* session);

	int do_PUTOUT_MJ(Player *player, int outmj_val);

	int handler_player_operater_ANG_GANG(Player* player, NetworkSessionBase* session);
	int handler_player_operater_MING_GANG(Player *player, NetworkSessionBase* session);
	int do_MING_GANG(Player *player);
	int handler_player_operater_ZI_MO(Player *player, NetworkSessionBase* session);
	int handler_bao_ting_req(Player *player, NetworkSessionBase* session);

	int handler_player_operater_PENG(Player *player, NetworkSessionBase* session);
	int handler_player_operater_FANG_GANG(Player *player, NetworkSessionBase* session);
	int handler_player_operater_FANG_PAO_HU(Player *player, NetworkSessionBase* session);
	int handler_player_operater_PASS(Player *player, NetworkSessionBase* session);
	int handler_player_operater_PASS2(Player *player, NetworkSessionBase* session);
	int do_pass(Player *player);

	int handler_player_operater_QIANG_GANG_HU(Player *player, NetworkSessionBase* session);
	int do_qiangganghu_timeout_pass(Player *player);

	int handler_player_dissolution_room_req(Player *player, NetworkSessionBase* session);
	int handler_player_dissolution_room_confirm(Player *player, NetworkSessionBase* session);
	int handler_player_ready(Player *player, NetworkSessionBase* session);
	int handler_speak_req(Player *player, NetworkSessionBase* session);
	int handler_del_player(Player *player, NetworkSessionBase* session);
	//通知所有人 某用户离开了这个桌子
	int handler_logout(Player *player, NetworkSessionBase* session);
	int handler_cancel_robot_op(Player *player, NetworkSessionBase* session);
	int send_all_end_info();
	int handler_nolmal_chart_req(Player *player, NetworkSessionBase* session);

	int confirm_cnt();
	int if_dissolution();

	bool if_que_men(Player *player, const Mj &mj);

	//logic
	//对别人打出的牌的进行判断
	bool check_peng(Player *player, Mj out_mj);
	bool check_fang_gang(Player *player, Mj out_mj);
	bool check_fang_pao_hu(Player*player, Mj out_mj, Player *out_mj_player);
	bool check_qiang_gang_hu(Player *player, Mj gang_mj, Player *qiang_gang_player);

	//对自己摸到的牌的判断
	bool check_ang_gang(Player *player, std::vector<int> &vec_gang_val);
	bool check_ang_gang(Player *player, Mj _mo_mj);
	bool check_ming_gang(Player *player, Mj _mo_mj);
	bool check_zi_mo_hu(Player *player);
	bool check_op_ting(Player *player, std::vector<int> &vec_ting_mjval);

	//玩家是否叫牌
	int check_jiaopai_flag(Player *player);
	//叫嘴玩家最大胡牌牌型
	int check_ting_max_cardtype(Player *player);

	//玩家操作
	int do_peng(Player *player, Player *out_player, Mj out_mj);   //碰
	int do_fang_gang(Player *player, Player *out_player, Mj out_mj);              //放杠
	int do_ang_gang(Player *player, Mj mj);                       //暗杠
	int do_ming_gang(Player *player, Mj mj);  //明杠

											  //自摸胡牌
	int do_zi_mo_hu(Player *player);
	//放炮胡	
	int do_fang_pao_hu(Player *player, Mj mj, Player *out_mj_player);
	//抢杠胡
	int do_qiang_gang_hu(Player *player, Mj mj, Player *qiang_gang_player);

	//算鸡
	void do_fangpaiji();//番牌鸡
	void do_gudingji(); //固定鸡
	void do_chongfengji(); //冲锋鸡
	void do_zherenji(); //责任鸡	
	void begin_robot_op_bc(Player *player);

};

#endif
